Skip to content

Conversation

@Mingguriguri
Copy link
Collaborator

@Mingguriguri Mingguriguri commented May 3, 2025

🌱WIL

이번 한 주의 소감을 작성해주세요!

  • 이번 주에는 발제 문제로 이분 탐색, 그 중에서도 매개변수 탐색에 대해 알게 되었다. 기존 이진 탐색은 정렬된 값 중에서 특정 원소를 찾는 방식이었다. 하지만 이 문제는 정답이 될 수 있는 "범위 내 값"을 이진 탐색으로 좁혀가야 했다. 처음에는 이게 너무 헷갈렸는데 이런 문제를 풀어볼 수 있어서 정말 다행이라는 생각이 들었다. 관련 문제를 많이 풀어서 내걸로 만들어야겠다.
  • 단지번호붙이기 문제에서는 "플러드 필"이라는 개념을 새로 알게 되었다. 미로 탐색 문제도 풀면서 오랜만에 그래프 문제인 BFS 문제를 풀게 되었다. DFS로 접근해야 할 지, BFS로 접근해야 할 지 헷갈리는 게 좀 있었지만 문제들을 풀면서 다시 리마인드 하게 되었다.
  • 이번 달(5월)에는 코테도 많아서 진짜 지금보다 더 많이 연습해야 할 것 같다. 이번 주는 살짝 뒷전이었던 코테연습.. 다음 주부터는 진짜 빡시게 해야겠다.

🚀주간 목표 문제 수: 4개

푼 문제


백준 #2110. 공유기 설치: 이분탐색 / 골드4

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 집 좌표를 오름차순 정렬한다.
  2. 공유기 사이의 거리 dist를 이진 탐색한다.
    • left = 1, right = 가장 먼 집 간 거리
  3. mid 값을 기준 거리로 공유기를 설치할 수 있는지를 판별한다.
  4. 설치 가능하다면 거리를 늘리고, 불가능하다면 줄인다.
  5. 최종적으로 가능한 최대 거리(mid)를 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline

N, C = map(int, input().split())  # N: 집 개수, C: 공유기 개수
houses = [int(input()) for _ in range(N)]  # 집 좌표 리스트
houses.sort()

left = 1  # 최소 거리
right = houses[N-1] - houses[0]
result = 0

while left <= right:
    mid = (left + right) // 2  # 현재 설정된 거리
    cnt = 1  # 공유기 최소 1대
    check = houses[0]

    for i in range(N):
        if houses[i] - check >= mid: # 현재 설정된 거리 이상이면 공유기 개수 늘리기
            cnt += 1
            check = houses[i]
    if cnt >= C:  # 공유기 설치 수가 C 이상이면, 공유기간 거리 늘리기
        left = mid + 1
        result = max(result, mid)
    else:  # 공유기 설치 수가 C보다 미만이면, 공유기간 거리 줄이기
        right = mid - 1

print(result)

💡TIL

배운 점이 있다면 입력해주세요

  • 기존 이진 탐색은 정렬된 값 중에서 특정 원소를 찾는 방식이었다.

  • 하지만 이 문제는 **정답이 될 수 있는 "범위 내 값"**을 이진 탐색으로 좁혀가야 했다.

  • 처음에는 이게 왜 이진 탐색인지 헷갈렸지만,

    "조건을 만족하는 값이 있는지 여부"를 탐색하는 과정이 매개변수 탐색이라는 것을 이해하고 나서 개념이 정리되었다.

  • 이진 탐색 = 정답을 직접 찾는 것이 아니라, 가능한지를 판단하며 답을 좁히는 과정임을 확실히 이해할 수 있었다.


백준 #1654. 랜선 자르기: 이분탐색 / 실버2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력 처리
    • K, N: 현재 가진 랜선의 수 K, 필요한 랜선의 수 N을 입력받는다.
    • arr: K개의 랜선 길이를 리스트로 저장한다.
  2. 탐색 범위 설정
    • start = 1: 만들 수 있는 최소 길이 (0은 나눌 수 없으므로 1부터 시작)
    • end = max(arr): 만들 수 있는 최대 길이 (가장 긴 랜선)
  3. 이분 탐색 루프 시작
    • startend 이하일 때까지 반복한다.
  4. 중간값 계산 (mid)
    • mid = (start + end) // 2: 현재 시도할 랜선의 길이로 설정
  5. 랜선 개수 계산
    • cnt = sum(x // mid for x in arr): 각 랜선을 mid 길이로 잘라서 만들 수 있는 랜선 총합을 구한다.
  6. 조건 검사 및 탐색 범위 조정
    • cnt >= N이면: 현재 길이로도 N개 이상 만들 수 있음 → 더 긴 길이도 가능할 수 있음 → start = mid + 1
    • cnt < N이면: 랜선이 부족함 → 더 짧은 길이 시도 → end = mid - 1
  7. 최대 길이 출력
    • end는 조건을 만족하는 최대 길이이므로 결과로 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline

K, N = map(int, input().split())  # K: 기존 랜선 수, N: 필요한 랜선 수
arr = [int(input()) for _ in range(K)]

start = 1
end = max(arr)

while start <= end:
    mid = (start + end) // 2  # 현재 시도할 랜선 길이
    cnt = sum(x // mid for x in arr)  # 해당 길이로 만들 수 있는 랜선 개수

    if cnt >= N:
        start = mid + 1  # 더 길게 잘라도 됨
    else:
        end = mid - 1  # 너무 길어서 N개 못 만듦

print(end)  # 조건을 만족하는 최대 길이

💡TIL

배운 점이 있다면 입력해주세요

  • 매개변수 탐색의 핵심은 “정답을 가정하고, 조건을 판단하는 함수”를 만드는 것이다.
  • 기존 이분 탐색은 정렬된 배열에서 값을 찾는 것이었다면, 매개변수 탐색은 **"범위 자체에서 정답을 찾아가는 과정"**이다.
  • 이 문제를 통해 그 개념을 확실하게 익힐 수 있었다.
  • 매개변수 탐색은 이외에도 공유기 설치, 징검다리 건너기, 예산 분배 등에서 자주 활용된다.

백준 #2178. 미로 탐색: 그래프 / 실버1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력 처리
    • N, M: 미로의 세로, 가로 크기를 입력받는다.
    • graph: 각 행마다 정수 리스트로 변환된 미로 정보를 2차원 리스트로 저장한다.
  2. BFS 함수 정의
    • bfs(x, y) 함수는 시작 좌표 (0, 0)에서 출발하여 목적지 (N-1, M-1)까지 최소 칸 수를 구하는 함수이다.
  3. 방향 설정
    • 상, 하, 좌, 우 네 방향을 탐색하기 위한 dx, dy 배열을 정의한다.
  4. 큐 초기화
    • 시작 위치 (x, y)를 큐에 삽입하고 BFS 탐색을 시작한다.
  5. 큐가 빌 때까지 반복
    • 현재 좌표 (x, y)를 꺼내고, 4방향에 대해 이동 가능한 위치인지 체크한다.
      • 범위를 벗어나면 continue
      • 벽(0)이면 continue
      • 이동 가능한 칸(1)이면:
        • graph[nx][ny] 값을 graph[x][y] + 1로 갱신 (거리 누적)
        • 해당 좌표를 큐에 삽입
  6. 탐색 종료 후 결과 반환
    • graph[N-1][M-1]에 저장된 값이 최소 칸 수이므로 이를 반환한다.
  7. 출력
    • print(bfs(0, 0))을 통해 결과 출력

🚩제출한 코드

import sys
from collections import deque
input = sys.stdin.readline

# 입력 처리
N, M = map(int, input().split())
graph = [list(map(int, input().strip())) for _ in range(N)]

def bfs(x, y):
    # 방향: 상, 하, 좌, 우
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]

    queue = deque()
    queue.append((x, y))

    while queue:
        x, y = queue.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            # 범위 벗어나면 무시
            if nx < 0 or nx >= N or ny < 0 or ny >= M:
                continue

            # 벽이면 무시
            if graph[nx][ny] == 0:
                continue

            # 이동 가능한 칸이면 거리 갱신 후 방문 처리
            if graph[nx][ny] == 1:
                graph[nx][ny] = graph[x][y] + 1
                queue.append((nx, ny))

    return graph[N-1][M-1]

print(bfs(0, 0))

💡TIL

배운 점이 있다면 입력해주세요

  • BFS 문제는 특히 격자형 탐색 문제, 미로 탈출, 불 퍼짐 문제 등에서 자주 등장한다. 처음에는 DFS로 풀어야 하는 줄 알고 헷갈렸는데 최단 거리나 격자형 탐색은 BFS로 풀어야 한다는 것을 알게 됐다.

백준 #2667. 단지번호 붙이기: 그래프 / 실버1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력 처리
    • n을 입력받고, n x n 크기의 2차원 리스트 graph를 생성한다.
  2. 탐색 방향 설정
    • 상, 하, 좌, 우를 나타내는 dx, dy 리스트를 정의한다.
  3. BFS 함수 정의
    • (x, y) 좌표를 시작으로 BFS를 수행한다.
    • 방문한 노드는 0으로 바꿔 재방문을 방지한다.
    • 큐를 사용하여 연결된 모든 1을 탐색하며 단지 내 집의 개수를 센다.
  4. 전체 격자 순회
    • 모든 좌표 (i, j)를 순회하며 graph[i][j] == 1인 경우 BFS를 호출한다.
    • BFS의 리턴값(단지 크기)을 result 리스트에 저장한다.
  5. 결과 출력
    • result 리스트를 오름차순으로 정렬한다.
    • 단지 수(len(result))와 각 단지에 속한 집의 수를 한 줄씩 출력한다.

🚩제출한 코드

from collections import deque

# 방향 벡터: 상, 하, 좌, 우
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

def bfs(start_x, start_y):
    queue = deque()
    queue.append((start_x, start_y))
    graph[start_x][start_y] = 0  # 방문 처리
    house_count = 1  # 단지 내 집 수

    while queue:
        x, y = queue.popleft()
        for i in range(4):  # 상하좌우 탐색
            nx, ny = x + dx[i], y + dy[i]

            # 좌표가 유효한지 확인
            if 0 <= nx < n and 0 <= ny < n and graph[nx][ny] == 1:
                graph[nx][ny] = 0  # 방문 처리
                queue.append((nx, ny))
                house_count += 1
    return house_count

# 입력
n = int(input())
graph = [list(map(int, input().strip())) for _ in range(n)]

result = []

# 모든 좌표 순회하며 BFS 수행
for i in range(n):
    for j in range(n):
        if graph[i][j] == 1:
            result.append(bfs(i, j))

# 결과 출력
result.sort()
print(len(result))
for count in result:
    print(count)

@Mingguriguri Mingguriguri self-assigned this May 3, 2025
Copy link
Collaborator

@zaqquum zaqquum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 주도 고생 많으셨습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 아래처럼 작성했는데 for문을 리스트 컴프리헨션 사용해서 한 줄로 축약한 것이 인상적입니다.

    for line in lines:
        cnt += line // mid

Copy link
Member

@YoonYn9915 YoonYn9915 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIL로 문제유형 및 핵심을 잘 정리해 주신 것 같습니다. 적어주신 것처럼 새로운 유형 많이 풀어보고 습득해야 될 것 같아요!
"탐색 대상은 답이 아니라 '조건'이다, 일반적인 이분 탐색은 값을 찾는 데 집중하지만, 이 문제는 mid가 될 수 있는 가장 큰 값을 찾기 위해 조건(cnt >= C)을 체크하고, 탐색 범위를 조정해 나간다."

@Mingguriguri Mingguriguri merged commit 762e804 into main May 6, 2025
@github-actions
Copy link

github-actions bot commented May 6, 2025

🔥2025-05 챌린지 진행 상황

👉 그래프

  • YoonYn9915: 0개 ❌
  • Mingguriguri: 2개 ❌

👉 DP

  • YoonYn9915: 2개 ❌
  • Mingguriguri: 0개 ❌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants